﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace XNAVE3D
{
    struct MyVertex : IVertexType
    {
        Vector3 pos;
        Vector3 normal;
        Vector2 text;
        Vector3 pos2;
        Vector3 normal2;

        public MyVertex(Vector3 p1, Vector3 n1, Vector2 tc, Vector3 p2, Vector3 n2)
        {
            pos = p1;
            normal = n1;
            text = tc;
            pos2 = p2;
            normal2 = n2;
        }
        private readonly static VertexDeclaration vertexDeclaration = new VertexDeclaration
        (
            new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
            new VertexElement(sizeof(float) * 3, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0),
            new VertexElement(sizeof(float) * 6, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
            new VertexElement(sizeof(float) * 8, VertexElementFormat.Vector3, VertexElementUsage.Position, 1),
            new VertexElement(sizeof(float) * 11, VertexElementFormat.Vector3, VertexElementUsage.Normal, 1));

        public VertexDeclaration VertexDeclaration { get { return vertexDeclaration; } }
    }

    class ModeloAnimation2
    {
        Vector3 position;
        public Model[] model;
        public Matrix myWorld = Matrix.Identity; Texture2D tex;
        int frame = 0; float contador;

        //VertexPositionTexture[] verts;  
        MyVertex[] verts;
        VertexBuffer vertexBuffer;
        short[] index;
        float[][] buffer;
        int size;
        Vector2[] ct;
        Effect effect;
        
        public ModeloAnimation2(Vector3 position, Model[] model, Texture2D tex, Effect e, GraphicsDevice g)
        {
            this.tex = tex;
            myWorld.Translation = position;
            this.position = position;
            this.model = model;
            effect = e;
            size = model[0].Meshes[0].MeshParts[0].VertexBuffer.VertexCount;
            buffer = new float[model.Length][];
            for (int i = 0; i < model.Length; i++)
            {
                buffer[i] = new float[size * 8];
                model[i].Meshes[0].MeshParts[0].VertexBuffer.GetData<float>(buffer[i]);
            }
            index = new short[model[0].Meshes[0].MeshParts[0].IndexBuffer.IndexCount];
            model[0].Meshes[0].MeshParts[0].IndexBuffer.GetData<short>(index);
            verts = new MyVertex[size];
            vertexBuffer = new VertexBuffer(g, typeof(MyVertex),
                verts.Length, BufferUsage.None);
            vertexBuffer.SetData<MyVertex>(verts);
            ct = new Vector2[size];
            int k = frame;
            int l = frame + 1;
            if (l == model.Length)
            {
                l = 0;
            }
            for (int i = 0; i < size; i++)
            {
                int j = i * 8;
                Vector3 p1 = new Vector3(this.buffer[k][j], -buffer[k][j + 2], -buffer[k][j + 1]);
                Vector3 n1 = new Vector3(this.buffer[k][j + 3], buffer[k][j + 4], buffer[k][j + 5]);
                ct[i] = new Vector2(this.buffer[0][j + 6], buffer[0][j + 7]);
                Vector3 p2 = new Vector3(this.buffer[l][j], -buffer[l][j + 2], -buffer[l][j + 1]);
                Vector3 n2 = new Vector3(this.buffer[l][j + 3], buffer[l][j + 4], buffer[l][j + 5]);
                verts[i] = new MyVertex(p1, n1, ct[i], p2, n2);
            }

            myWorld *= Matrix.CreateScale(5);
            myWorld *= Matrix.CreateRotationY(MathHelper.ToRadians(180));
        }

        float divisor = 0.001f;
        public void Update(GameTime gameTime, GraphicsDevice g)
        {
            myWorld.Translation = position;
            //if (Keyboard.GetState().IsKeyDown(Keys.Up) && divisor < 0)
            //{
            //    divisor += 0.0005f;
            //}
            //if (Keyboard.GetState().IsKeyDown(Keys.Down) && divisor >0.01f)
            //{
            //    divisor -= 0.0005f;
            //}
            if (Keyboard.GetState().IsKeyDown(Keys.Q))
            {
                myWorld *= Matrix.CreateRotationY(MathHelper.ToRadians(-3));
            }
            if (Keyboard.GetState().IsKeyDown(Keys.E))
            {
                myWorld *= Matrix.CreateRotationY(MathHelper.ToRadians(3));
            }
            if (Keyboard.GetState().IsKeyDown(Keys.Z) && divisor >= 0.5f)
            {
                divisor -= 0.05f;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.X) && divisor <= 13)
            {
                divisor += 0.05f;
            }
            contador += (float)gameTime.ElapsedGameTime.TotalMilliseconds * divisor;

            if (contador >= 1.0f)
            {
                contador = 0;
                int k = frame;
                int l = frame + 1;
                if (l >= model.Length)
                {
                    l = 0;
                    frame = 0;
                }
                else
                {
                    frame++;
                }

                for (int i = 0; i < size; i++)
                {
                    int j = i * 8;
                    Vector3 p1 = new Vector3(this.buffer[k][j], -buffer[k][j + 2], -buffer[k][j + 1]);
                    Vector3 n1 = new Vector3(this.buffer[k][j + 3], buffer[k][j + 4], buffer[k][j + 5]);
                    ct[i] = new Vector2(this.buffer[0][j + 6], buffer[0][j + 7]);
                    Vector3 p2 = new Vector3(this.buffer[l][j], -buffer[l][j + 2], -buffer[l][j + 1]);
                    Vector3 n2 = new Vector3(this.buffer[l][j + 3], buffer[l][j + 4], buffer[l][j + 5]);
                    verts[i] = new MyVertex(p1, n1, ct[i], p2, n2);
                }
            }


        }
        public void Draw(Matrix view, Matrix projection, GraphicsDevice g)
        {
            position = new Vector3(10, 10, 8);

            g.SetVertexBuffer(vertexBuffer);
            effect.CurrentTechnique = effect.Techniques["Technique1"];
            effect.Parameters["View"].SetValue(view);
            effect.Parameters["Projection"].SetValue(projection);
            effect.Parameters["World"].SetValue(myWorld);
            effect.Parameters["colorTexture"].SetValue(tex);
            effect.Parameters["t"].SetValue(contador);

            Matrix matInvTrans = Matrix.Transpose(myWorld);
            matInvTrans = Matrix.Invert(matInvTrans);
            effect.Parameters["Inverse"].SetValue(matInvTrans);

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                g.DrawUserIndexedPrimitives<MyVertex>(PrimitiveType.TriangleList, verts, 0, verts.Length, index, 0, index.Length / 3);
            }

        }
    }
}
